﻿//Script created by Merlin and Xiexe.
using UnityEngine;
using UnityEditor;
using System.Collections;
using System.IO;

public class XSTextureMerger : EditorWindow
{

    private enum resolutions
    {
        Tiny_256x256,
        Small_512x512,
        Medium_1024x1024,
        Large_2048x2048,
        VeryLarge_4096x4096,
        Why_8192x8192
    }

    private enum EChannels
    {
        None,
        Red,
        Green,
        Blue,
        Alpha
    }

    private enum ETextures
    {
        None,
        Tex1,
        Tex2,
        Tex3,
        Tex4
    }


    private Texture2D[] textures = new Texture2D[4];
    private EChannels[] texChannels = new EChannels[4];
    private ETextures[] pickTexture = new ETextures[4];
    private bool[] invertChannel = new bool[4];

    private static int srcTex;
    private resolutions res;
    private Vector2 scrollPos;
    private static int resolution;
    private static string finalFilePath;
    private static Color outColor;
    private static Color[] texColors = new Color[4];

	private static float progress;
	[MenuItem("Tools/Xiexe/XSToon/Texture Merger")]
    static public void Init()
    {
        XSTextureMerger window = EditorWindow.GetWindow<XSTextureMerger>(false, "XSToon: Texture Merger", true);
        window.minSize = new Vector2(500, 300);
        window.maxSize = new Vector2(500, 500);
    }

    public void OnGUI()
    {
        scrollPos = EditorGUILayout.BeginScrollView(scrollPos);
        
        GUILayout.BeginHorizontal();
            GUILayout.Space(105);
                XSStyles.doLabel("1");
            GUILayout.Space(105);
                XSStyles.doLabel("2");
            GUILayout.Space(105);
                XSStyles.doLabel("3");
            GUILayout.Space(105);
                XSStyles.doLabel("4");
        GUILayout.EndHorizontal();

        XSStyles.SeparatorThin();
        GUILayout.BeginHorizontal();
        for (int i = 0; i < 4; i++)
        {
            EditorGUIUtility.labelWidth = 0.01f;
            textures[i] = (Texture2D)EditorGUILayout.ObjectField(new GUIContent("", ""), textures[i], typeof(Texture2D), true);

        }
        GUILayout.EndHorizontal();

        float oldLabelWidth = EditorGUIUtility.labelWidth;
        EditorGUIUtility.labelWidth = 40;
        GUIStyle headerStyle = EditorStyles.boldLabel;
        headerStyle.alignment = TextAnchor.UpperLeft;
        headerStyle.fontStyle = FontStyle.Bold;
        headerStyle.stretchWidth = true;

        XSStyles.SeparatorThin();
        EditorGUILayout.BeginHorizontal();
        GUILayout.Label("Output Channel:", headerStyle);

        GUILayout.Label("R", headerStyle);
        GUILayout.Label("G", headerStyle);
        GUILayout.Label("B", headerStyle);
        GUILayout.Label("A", headerStyle);
        EditorGUILayout.EndHorizontal();

        GUILayout.BeginHorizontal();
        GUILayout.Label("Src Texture:");
        GUILayout.Space(20);
            for(int i = 0; i < 4; i++)
            {
                pickTexture[i] = (ETextures)EditorGUILayout.EnumPopup("", pickTexture[i]);
            }
        GUILayout.EndHorizontal();

        GUILayout.BeginHorizontal();
        GUILayout.Label("Src Channel:");
        GUILayout.Space(17);
            for(int i = 0; i < 4; i++)
            {
                texChannels[i] = (EChannels)EditorGUILayout.EnumPopup("", texChannels[i]);
            }
        GUILayout.EndHorizontal();
        GUILayout.BeginHorizontal();
            GUILayout.Label("Invert Channel:");
            for(int i = 0; i < 4; i++)
            {
                invertChannel[i] = EditorGUILayout.Toggle("", invertChannel[i]);
            }
        GUILayout.EndHorizontal();
        
        GUILayout.Space(20);
        EditorGUILayout.EndScrollView();

        //Button and Resolution
        GUILayout.BeginVertical();
            XSStyles.doLabel("Resolution");
            
            GUILayout.BeginHorizontal();
                GUILayout.Space(175);
                    res = (resolutions)EditorGUILayout.EnumPopup("", res);
                GUILayout.Space(175);
            GUILayout.EndHorizontal();
                
            if(GUILayout.Button("Merge Channels"))
            {
				if (progress < 2)
				{
					EditorUtility.DisplayProgressBar("XSToon Texture Merger", "Merging and compressing new texture...", (float)(progress / 2));
				}

			//Set target textures to be ReadWriteable

			for (int i = 0; i < textures.Length; i++)
                {
                    if(textures[i] == null)
                        break;

                    string texturePath = AssetDatabase.GetAssetPath(textures[i]);
                    TextureImporter texture = (TextureImporter)TextureImporter.GetAtPath(texturePath);
                    if (texture != null)
                    {
                        texture.isReadable = true;
                        texture.SaveAndReimport();
                    }
                }
               
                switch(res)
                {
                    case resolutions.Tiny_256x256:
                        resolution = 256;
                    break;

                    case resolutions.Small_512x512:
                        resolution = 512;
                    break;

                    case resolutions.Medium_1024x1024:
                        resolution = 1024;
                    break;

                    case resolutions.Large_2048x2048:
                        resolution = 2048;
                    break;

                    case resolutions.VeryLarge_4096x4096:
                        resolution = 4096;
                    break;

                    case resolutions.Why_8192x8192:
                        resolution = 8192;
                    break;
                }

                XSStyles.findAssetPath(finalFilePath);
                finalFilePath = EditorUtility.SaveFilePanel("Save Merged Texture", finalFilePath + "/Textures/", "mergedTex.png", "png");

				
                Texture2D newTexture = new Texture2D(resolution, resolution, TextureFormat.RGBA32, false);

                //Get Colors textures and write them to the proper channel

                    for (int y = 0; y <  resolution; y++)
                    {
                        for (int x = 0; x <  resolution; x++)
                        {
                            float u = x / (float)resolution;
                            float v = y / (float)resolution;
                            
							// Grab out the texture values into an array for later lookup. Could probably just be done at the moment the texture color is needed.
                            for(int i = 0; i < textures.Length; i++)
                            {
                                if(textures[i] != null)
                                {
                                    texColors[i] = textures[i].GetPixelBilinear(u, v);
                                }
								else
								{
									texColors[i] = new Color(0, 0, 0, 1);
								}
                            }
							
							Color outputColor = new Color(0, 0, 0, 1);
							
							// Iterate the output RGBA channels
							for (int i = 0; i < 4; i++)
							{			
								// Convert the enums to indices we can use. 'None' will turn into -1 which will be discarded as invalid.
								int srcTexIdx = ((int)pickTexture[i]) - 1;
								int srcChannelIdx = ((int)texChannels[i]) - 1;
								
								// Go through each channel in the output color and assign it
								if (srcTexIdx >= 0 && srcChannelIdx >= 0)
								{
									outputColor[i] = texColors[srcTexIdx][srcChannelIdx];
                                    
                                    //Allow you to invert specific channels. 
                                    if (invertChannel[i])
                                    {
                                        outputColor[i] = 1f - outputColor[i];
                                    }
                                }
							}	
							
                            newTexture.SetPixel(x, y, outputColor);
                        }
                    }
				progress += 1;
				newTexture.Apply();
                ExportTexture(newTexture);
            }
            
            GUILayout.Space(10);
        GUILayout.EndVertical();

		

		EditorGUIUtility.labelWidth = oldLabelWidth;
    }

    private static void ExportTexture(Texture2D newTexture)
    {
        var pngData = newTexture.EncodeToPNG();

        if (pngData != null)
        {
            File.WriteAllBytes(finalFilePath, pngData);
            AssetDatabase.Refresh();
        }
		progress += 1;
		EditorUtility.ClearProgressBar();
	}
}
